package com.plian.system.service.pm.realproperty.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.plian.Tools.*;
import com.plian.Tools.pagedata.PageData;
import com.plian.system.cache.UserCache;
import com.plian.system.constant.sys.FormStatusConstant;
import com.plian.system.constant.sys.FormTypeConstant;
import com.plian.system.constant.yth.YthConstant;
import com.plian.system.entity.pm.realproperty.RealProperty;
import com.plian.system.entity.sys.ApprovalMessage;
import com.plian.system.entity.sys.Org;
import com.plian.system.enumeratea.LandStatus;
import com.plian.system.mapper.pm.realproperty.RealPropertyMapper;
import com.plian.system.mapper.yth.realproperty.CancelRecordMapper;
import com.plian.system.mybatis.base.BaseFlowService;
import com.plian.system.mybatis.base.BaseServiceImpl;
import com.plian.system.service.bt.baseinfo.BaseInfoService;
import com.plian.system.service.pm.realproperty.IRealPropertyDisposalService;
import com.plian.system.service.pm.realproperty.IRealPropertyLatestService;
import com.plian.system.service.sys.code.IFormCodeService;
import com.plian.system.service.sys.file.FileService;
import com.plian.system.service.sys.message.IApprovalMessageService;
import com.plian.system.service.sys.orgzation.IOrgService;
import com.plian.system.service.wf.FormWorkflowService;
import com.plian.system.vo.pm.realproperty.RealPropertyVO;
import com.plian.system.vo.yth.YthResult;
import com.plian.system.wrapper.pm.realproperty.RealPropertyWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.plian.system.constant.sys.FormStatusConstant.UNREVIEWED;

/**
 * 不动产登记信息表 处置 服务实现类
 *
 * @author BladeX
 * @since 2021-06-01
 */
@Slf4j
@Service
@AllArgsConstructor
public class RealPropertyDisposalServiceImpl extends BaseServiceImpl<RealPropertyMapper, RealProperty> implements IRealPropertyDisposalService, BaseFlowService {

    private FileService fileService;

    private FormWorkflowService formWorkflowService;

    private IFormCodeService formCodeService;

    private RealPropertyWrapper realPropertyWrapper;

    private IRealPropertyLatestService realPropertyLatestService;

    private IOrgService orgService;

    private IApprovalMessageService approvalMessageService;

    private CancelRecordMapper cancelRecordMapper;

    private BaseInfoService baseInfoService;
    @Override
    public boolean saveOrUpdate(RealProperty realProperty) {
        boolean flag = false;
        if (realProperty.getId() == null){
            flag = true;
            realProperty.setCode(formCodeService.getCode(FormTypeConstant.PM_REAl_PROPERTY_DISPOSAL));
            realProperty.setFormType(String.valueOf(FormTypeConstant.PM_REAl_PROPERTY_DISPOSAL));
            realProperty.setVersion(realProperty.getVersion() + 1);
            realProperty.setIsLatest(1);
            realProperty.setLandStatus(LandStatus.DISPOSAL_AUDIT.getStatus());
            updateLangStatus(realProperty.getInitialId(), LandStatus.DISPOSAL_AUDIT.getStatus());
        }

        boolean result = super.saveOrUpdate(realProperty);
        if (flag){
            fileService.saveAll(String.valueOf(realProperty.getId()), realProperty.getDocList());
        }else {
            fileService.edit(String.valueOf(realProperty.getId()), realProperty.getDocList());
        }

        return result;
    }

    @Override
    public boolean deleteLogic(List<Long> ids) {
        for (Long id : ids) {
            RealProperty realProperty = getById(id);
            if (realProperty == null) {
                return false;
            } else if (realProperty.getStatus() != null &&
                    (realProperty.getStatus() != FormStatusConstant.STASH && realProperty.getStatus() != FormStatusConstant.UNREVIEWED)) {
                return false;
            }
            updateLangStatus(realProperty.getInitialId(), LandStatus.ADJUSTABLE.getStatus());
            formWorkflowService.deleteProcessInstance(String.valueOf(id));
            update(Wrappers.<RealProperty>lambdaUpdate()
                    .eq(RealProperty::getInitialId, realProperty.getInitialId())
                    .eq(RealProperty::getVersion, realProperty.getVersion() - 1)
                    .set(RealProperty::getIsLatest, 2));
        }
        boolean result = super.deleteLogic(ids);
        return result;
    }

    @Override
    public HashMap<String,Object> commit(String id) {
        handleStatus(Long.valueOf(id), FormStatusConstant.FLOW, null);

        //将需要提交的流程变量返回，用于工作流侧
        return new HashMap<String,Object>();
    }

    @Override
    public Boolean finish(String id) {
        /**
         * 设置审批人和审批时间
         */
        RealProperty realProperty = getById(id);
        updateLangStatus(realProperty.getInitialId(), LandStatus.DISPOSAL.getStatus());
        updateIsLatest(realProperty.getInitialId());

        realProperty.setApprovedUser(TokenUtil.getTokenUserId());
        Date now = DateUtil.now();
        realProperty.setApprovedTime(now);
        realProperty.setIsLatest(2);
        realProperty.setLandStatus(LandStatus.DISPOSAL.getStatus());
        updateById(realProperty);

        return handleStatus(Long.valueOf(id), FormStatusConstant.FINISH, "审批通过");
    }

    @Override
    public Boolean reject(String id, int formState, String comment) {
        return handleStatus(Long.valueOf(id), formState, comment);
    }


    @Override
    public List<PageData> findByIds(List<String> formIds) {
        QueryWrapper<RealProperty> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id", Func.toLongList(StringUtils.join(formIds, StringPool.COMMA)));
        List<RealProperty> realPropertyList = list(queryWrapper);
        List<RealPropertyVO> realPropertyVOS = realPropertyWrapper.entityToVO(realPropertyList);
        List<PageData> pageDataList = new ArrayList<>();
        try{
            if (CollectionUtil.isNotEmpty(realPropertyVOS)){
                for (RealPropertyVO vo : realPropertyVOS){
                    PageData pd = new PageData();
                    pd.put("id", vo.getId());
                    pd.put("UNITNAME", vo.getFillingUnitName());
                    pd.put("APPLICANTNAME", vo.getCreateUserName());
                    pd.put("applicantId", vo.getCreateUser());
                    pd.put("applyOrganizationId", vo.getFillingUnitId());
                    pd.put("formType", FormTypeConstant.PM_REAl_PROPERTY_DISPOSAL);
                    pd.put("orgName", vo.getFillingUnitName());
                    pageDataList.add(pd);
                }
            }

            return pageDataList;
        } catch (Exception e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
        }
        return pageDataList;
    }

    @Override
    public List<Integer> getFormType() {
        return Arrays.asList(FormTypeConstant.PM_REAl_PROPERTY_DISPOSAL);
    }

    @Override
    public void goBackToStash(String formId) {
        Long id = Long.valueOf(formId);
        RealProperty realProperty = getById(id);
        if (realProperty.getStatus() == FormStatusConstant.FINISH){
            LambdaUpdateWrapper<RealProperty> updateWrapper = new LambdaUpdateWrapper<>();
            update(updateWrapper.eq(RealProperty::getId, id)
                    .set(RealProperty::getApprovedUser, null).set(RealProperty::getApprovedTime, null));
            updateLangStatus(realProperty.getInitialId(), LandStatus.DISPOSAL_AUDIT.getStatus());
            updateIsLatest(realProperty.getInitialId());
            List<RealProperty> realPropertyList = list(new LambdaQueryWrapper<RealProperty>().eq(RealProperty::getInitialId, id)
                    .orderByDesc(RealProperty::getVersion));
            if (CollectionUtil.isNotEmpty(realPropertyList) && realPropertyList.size() > 1){
                RealProperty property = realPropertyList.get(1);
                property.setIsLatest(2);
                updateById(property);
            }
        }

        handleStatus(Long.valueOf(formId), UNREVIEWED, null);
    }

    /**
     * 统一处理状态机事件方法
     * @param id 主键
     * @param updateStatus 更新状态
     * @return boolean
     */
    private Boolean handleStatus(Long id, int updateStatus, String comment) {
        try {
            RealProperty realProperty = getById(id);
            realProperty.setStatus(updateStatus);
            if (YthConstant.DATA_NINGBO.equals(realProperty.getDataSource())){
                if (updateStatus == FormStatusConstant.FINISH || updateStatus == FormStatusConstant.REJECT){
                    ApprovalMessage approvalMessage = new ApprovalMessage();
                    approvalMessage.setDataSourceId(realProperty.getDataSourceId());
                    approvalMessage.setOpinion(comment);
                    approvalMessage.setIsApprove(updateStatus == FormStatusConstant.FINISH ? 2 : 1);
                    approvalMessage.setIsSend(1);
                    approvalMessage.setDataSourceType(YthConstant.DATA_NINGBO);
                    approvalMessage.setFilingUserName(UserCache.userIdToName(TokenUtil.getTokenUserId()));
                    approvalMessage.setFormType(Integer.valueOf(realProperty.getFormType()));
                    approvalMessage.setFilingCode(realProperty.getCode());
                    approvalMessageService.save(approvalMessage);
                }
            }
            return updateById(realProperty);
        } catch (Exception e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
            return false;
        }
    }

    @Override
    public boolean submit(RealProperty realProperty) {
        if (!Optional.ofNullable(realProperty.getStatus()).isPresent()){
            realProperty.setStatus(FormStatusConstant.UNREVIEWED);
        }

        boolean result = saveOrUpdate(realProperty);
        HashMap<String, Object> processVariable = new HashMap<>();
        formWorkflowService.startProcessAndSimulate(String.valueOf(realProperty.getId()),realProperty.getFormType(),processVariable);
        return result;
    }

    @Override
    public String ythSubmitBatch(String data) {
        YthResult ythResult = new YthResult();
        //成功的id集合
        List<String> successIds = new ArrayList<>();
        //失败的id集合
        List<String> failIds = new ArrayList<>();
        //失败的原因
        List<String> failReasons = new ArrayList<>();
        //将json字符串转换成list
        List<RealProperty> dataList = JSON.parseArray(data, RealProperty.class);
        if (CollectionUtil.isEmpty(dataList)){
            failReasons.add("数据为空");
            ythResult.setFailReason(StringUtils.join(failReasons, StringPool.COMMA));
            return JSON.toJSONString(ythResult);
        }
        List<RealProperty> canSubmitList = list(Wrappers.<RealProperty>lambdaQuery()
                .ne(RealProperty::getLandStatus, LandStatus.DISPOSAL.getStatus())
                .ne(RealProperty::getLandStatus, LandStatus.CHANGE_AUDIT.getStatus())
                .eq(RealProperty::getFormType, FormTypeConstant.PM_REAl_PROPERTY)
                .eq(RealProperty::getDataSource, YthConstant.DATA_NINGBO));
        Map<String, RealProperty> canSubmitMap = canSubmitList.stream().collect(Collectors.toMap(RealProperty::getDataSourceId, Function.identity()));

        List<RealProperty> flowList = list(new LambdaQueryWrapper<RealProperty>()
                .eq(RealProperty::getDataSource, YthConstant.DATA_NINGBO)
                .eq(RealProperty::getStatus, FormStatusConstant.FLOW)
                .eq(RealProperty::getFormType, FormTypeConstant.PM_REAl_PROPERTY_DISPOSAL));
        List<Long> cantSubmitList = flowList.stream().map(RealProperty::getInitialId).collect(Collectors.toList());

        List<RealProperty> oldList = list(new LambdaQueryWrapper<RealProperty>()
                .eq(RealProperty::getFormType, FormTypeConstant.PM_REAl_PROPERTY_DISPOSAL)
                .in(RealProperty::getStatus, Stream.of(FormStatusConstant.STASH,
                        FormStatusConstant.UNREVIEWED, FormStatusConstant.REJECT).collect(Collectors.toList())));
        Map<Long, RealProperty> oldMap = oldList.stream().collect(Collectors.toMap(RealProperty::getInitialId, Function.identity()));
        List<RealProperty> latestList = realPropertyLatestService.findLatestList(null, null);
        Map<Long, RealProperty> latestMap = latestList.stream().collect(Collectors.toMap(RealProperty::getInitialId, Function.identity()));

        List<Org> orgList = orgService.getYthOrgList();
        Map<String, Org> dataSourceIdOrgMap = orgList.stream().collect(Collectors.toMap(Org::getDataSourceId, Function.identity()));
        List<RealProperty> submitList = new ArrayList<>();
        List<Long> updateLandStatusList = new ArrayList<>();
        Date now = new Date();
        for (RealProperty realProperty : dataList){
            if (realProperty.getRealPropertyNature() == null ||
                    (realProperty.getRealPropertyNature() != 1 && realProperty.getRealPropertyNature() != 2)){
                failIds.add(realProperty.getDataSourceId());
                failReasons.add(realProperty.getDataSourceId() + "realPropertyNature 错误");
                continue;
            }
            if (!canSubmitMap.containsKey(String.valueOf(realProperty.getInitialId()))){
                failIds.add(realProperty.getDataSourceId());
                failReasons.add(realProperty.getDataSourceId() + "该不动产不可进行注销");
                continue;
            }

            if (cantSubmitList.contains(realProperty.getInitialId())){
                failIds.add(realProperty.getDataSourceId());
                failReasons.add("该不动产在注销流程中");
                continue;
            }
            if (successIds.contains(realProperty.getDataSourceId())){
                failIds.add(realProperty.getDataSourceId());
                failReasons.add(realProperty.getDataSourceId() + "id重复");
                continue;
            }

            successIds.add(realProperty.getDataSourceId());
            RealProperty initialRealProperty = canSubmitMap.get(String.valueOf(realProperty.getInitialId()));
            if (oldMap.containsKey(initialRealProperty.getInitialId())){
                realProperty.setId(oldMap.get(initialRealProperty.getInitialId()).getId());
                realProperty.setCode(oldMap.get(initialRealProperty.getInitialId()).getCode());
                realProperty.setUpdateTime(now);
            }else {
                realProperty.setCreateTime(now);
                realProperty.setCode(formCodeService.getCode(FormTypeConstant.PM_REAl_PROPERTY_DISPOSAL));
            }
            initialRealProperty.setInitialId(initialRealProperty.getInitialId());
            if (StringUtil.isNotBlank(realProperty.getOrgId()) && dataSourceIdOrgMap.containsKey(realProperty.getOrgId())){
                realProperty.setOrgId(dataSourceIdOrgMap.get(realProperty.getOrgId()).getId());
            }
            if (StringUtil.isNotBlank(realProperty.getEntrustUnitId()) && dataSourceIdOrgMap.containsKey(realProperty.getEntrustUnitId())){
                realProperty.setEntrustUnitId(dataSourceIdOrgMap.get(realProperty.getEntrustUnitId()).getId());
            }
            if (StringUtil.isNotBlank(realProperty.getFillingUnitId()) && dataSourceIdOrgMap.containsKey(realProperty.getFillingUnitId())){
                realProperty.setFillingUnitId(dataSourceIdOrgMap.get(realProperty.getFillingUnitId()).getId());
                realProperty.setCreateCompanyId(realProperty.getFillingUnitId());
            }
            RealProperty latestRealProperty = latestMap.get(initialRealProperty.getInitialId());
            realProperty.setDataSource(YthConstant.DATA_NINGBO);
            realProperty.setFormType(String.valueOf(FormTypeConstant.PM_REAl_PROPERTY_DISPOSAL));
            realProperty.setVersion(latestRealProperty.getVersion() + 1);
            realProperty.setLastVersionId(latestRealProperty.getId());
            updateLandStatusList.add(realProperty.getInitialId());
            realProperty.setLandStatus(LandStatus.DISPOSAL_AUDIT.getStatus());
            realProperty.setIsDeleted(0);
            submitList.add(realProperty);
        }

        if (CollectionUtil.isNotEmpty(submitList)){
            saveOrUpdateBatch(submitList);
            updateLangStatus(updateLandStatusList, LandStatus.DISPOSAL_AUDIT.getStatus());
        }

        ythResult.setSuccessIds(successIds);
        ythResult.setFailIds(failIds);
        ythResult.setFailReason(StringUtils.join(failReasons, StringPool.COMMA));
        //ythResult转换成json字符串
        return JSON.toJSONString(ythResult);
    }


    private void updateLangStatus(Long initialId, int landStatus){
        update(new LambdaUpdateWrapper<RealProperty>().eq(RealProperty::getInitialId, initialId).set(RealProperty::getLandStatus, landStatus));
    }

    private void updateLangStatus(List<Long> initialIdList, int landStatus){
        update(new LambdaUpdateWrapper<RealProperty>().in(RealProperty::getInitialId, initialIdList).set(RealProperty::getLandStatus, landStatus));
    }

    private void updateIsLatest(Long initialId){
        update(new LambdaUpdateWrapper<RealProperty>().eq(RealProperty::getInitialId, initialId)
                .eq(RealProperty::getIsLatest, 2).set(RealProperty::getIsLatest, 1));
    }
}
